Optimizing my Ford-Fulkerson implementation for sparse graphs.
[and.git] / 563 - Crimewave / 563.2.cpp
blobfd5828d87216d9f4d7324dd318b130459a112e31
1 using namespace std;
2 #include <algorithm>
3 #include <iostream>
4 #include <iterator>
5 #include <sstream>
6 #include <fstream>
7 #include <cassert>
8 #include <climits>
9 #include <cstdlib>
10 #include <cstring>
11 #include <string>
12 #include <cstdio>
13 #include <vector>
14 #include <cmath>
15 #include <queue>
16 #include <deque>
17 #include <stack>
18 #include <map>
19 #include <set>
21 #define foreach(x, v) for (typeof (v).begin() x = (v).begin(); x != (v).end(); ++x)
22 #define For(i, a, b) for (int i=(a); i<(b); ++i)
23 #define D(x) cout << #x " is " << x << endl
25 /////////////// Maximum flow for sparse graphs ///////////////
26 /////////////// Complexity: O(V * E^2) ///////////////
29 Usage:
30 Call initialize_max_flow();
31 Create graph using add_edge(u, v, c);
32 max_flow(source, sink);
34 WARNING: The algorithm writes on the cap array. The capacity
35 is not the same after having run the algorithm. If you need
36 to run the algorithm several times on the same graph, backup
37 the cap array.
40 namespace Flow {
41 // Maximum number of nodes
42 const int MAXN = 51 * 51 * 2;
43 // Maximum number of edges
44 // IMPORTANT: Remember to consider the backedges. For
45 // every edge we actually need two! That's why we have
46 // multiply by two at the end.
47 const int MAXE = MAXN * 6 * 2;
48 const int oo = INT_MAX / 4;
49 int first[MAXN];
50 int next[MAXE];
51 int adj[MAXE];
52 int cap[MAXE];
53 int current_edge;
56 Builds a directed edge (u, v) with capacity c.
57 Note that actually two edges are added, the edge
58 and its complementary edge for the backflow.
60 int add_edge(int u, int v, int c){
61 adj[current_edge] = v;
62 cap[current_edge] = c;
63 next[current_edge] = first[u];
64 first[u] = current_edge++;
66 adj[current_edge] = u;
67 cap[current_edge] = 0;
68 next[current_edge] = first[v];
69 first[v] = current_edge++;
72 void initialize_max_flow(){
73 current_edge = 0;
74 memset(next, -1, sizeof next);
75 memset(first, -1, sizeof first);
78 int q[MAXN];
79 int incr[MAXN];
80 int arrived_by[MAXN];
81 //arrived_by[i] = The last edge used to reach node i
82 int find_augmenting_path(int src, int snk){
84 Make a BFS to find an augmenting path from the source
85 to the sink. Then pump flow through this path, and
86 return the amount that was pumped.
88 memset(arrived_by, -1, sizeof arrived_by);
89 int h = 0, t = 0;
90 q[t++] = src;
91 arrived_by[src] = -2;
92 incr[src] = oo;
93 while (h < t && arrived_by[snk] == -1){ //BFS
94 int u = q[h++];
95 for (int e = first[u]; e != -1; e = next[e]){
96 int v = adj[e];
97 if (arrived_by[v] == -1 && cap[e] > 0){
98 arrived_by[v] = e;
99 incr[v] = min(incr[u], cap[e]);
100 q[t++] = v;
105 if (arrived_by[snk] == -1) return 0;
107 int cur = snk;
108 int neck = incr[snk];
109 while (cur != src){
110 //Remove capacity from the edge used to reach
111 //node "cur", and add capacity to the backedge
112 cap[arrived_by[cur]] -= neck;
113 cap[arrived_by[cur] ^ 1] += neck;
114 //move backwards in the path
115 cur = adj[arrived_by[cur] ^ 1];
117 return neck;
120 int max_flow(int src, int snk){
121 int ans = 0, neck;
122 while ((neck = find_augmenting_path(src, snk)) != 0){
123 ans += neck;
125 return ans;
128 int rows, cols;
129 inline int in(int u){ return 2*u; }
130 inline int out(int u){ return 2*u + 1; }
131 inline int number(int r, int c){ return r * cols + c; }
133 void print_edges(int u){
134 printf("Edges going out from %d:\n", u);
135 for (int e = Flow::first[u]; e != -1; e = Flow::next[e]){
136 printf("(v = %d, cap = %d)\n", Flow::adj[e], Flow::cap[e]);
140 int main(){
141 int cases;
142 for(scanf("%d", &cases); cases--; ){
143 int banks;
144 if (scanf("%d %d %d", &rows, &cols, &banks) != 3) break;
146 int source = rows * cols, sink = source + 1;
148 Flow::initialize_max_flow();
150 for (int k=0; k<banks; ++k){
151 int r, c;
152 scanf("%d %d", &r, &c);
153 r--, c--;
154 Flow::add_edge(out(number(r, c)), in(sink), 1);
157 for (int i=0; i<rows; ++i){
158 for (int j=0; j<cols; ++j){
159 if (i == 0 || i == rows - 1 || j == 0 || j == cols - 1){ //node lies on the border
160 Flow::add_edge(out(source), in(number(i, j)), 1);
162 if (i - 1 >= 0){
163 Flow::add_edge(out(number(i, j)), in(number(i-1, j)), 1);
165 if (i + 1 < rows){
166 Flow::add_edge(out(number(i, j)), in(number(i+1, j)), 1);
168 if (j - 1 >= 0){
169 Flow::add_edge(out(number(i, j)), in(number(i, j-1)), 1);
171 if (j + 1 < cols){
172 Flow::add_edge(out(number(i, j)), in(number(i, j+1)), 1);
177 for (int i=0; i<rows; ++i){
178 for (int j=0; j<cols; ++j){
179 Flow::add_edge(in(number(i, j)), out(number(i, j)), 1);
182 Flow::add_edge(in(source), out(source), Flow::oo);
183 Flow::add_edge(in(sink), out(sink), Flow::oo);
186 printf("in nodes:\n");
187 for (int i=0; i<rows; ++i){
188 for (int j=0; j<cols; ++j){
189 print_edges(in(number(i, j)));
192 printf("out nodes:\n");
193 for (int i=0; i<rows; ++i){
194 for (int j=0; j<cols; ++j){
195 print_edges(out(number(i, j)));
199 print_edges(in(source));
200 print_edges(out(source));
202 print_edges(in(sink));
203 print_edges(out(sink));
206 int f = Flow::max_flow(in(source), out(sink));
208 printf("%s\n", f == banks ? "possible" : "not possible");
210 return 0;